#ifdef CNIX
#include <asm/regs.h>
#include <asm/system.h>
#include <cnix/kernel.h>
#include <cnix/fs.h>
#include <cnix/string.h>
#include <cnix/mm.h>
#include <cnix/util.h>
#else
#include <stdio.h>
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#endif


void elf_free(void *p)
{
#ifdef CNIX
        kfree(p);
#else
	free(p);
#endif
}

void *elf_malloc(int size)
{
#ifdef CNIX
        return kmalloc(size, PageWait);
#else
	return malloc(size);
#endif
}

void *elf_realloc(void *p, int size)
{
#ifdef CNIX
        return krealloc(p, size);
#else
	return realloc(p, size);
#endif
}

#ifdef CNIX
extern int __do_fstat(int fd, struct stat * statbuf, BOOLEAN kernel);

void * get_file_buffer(const char *filename)
{
	void *ptr = NULL;
	int fd;
	struct stat st;

	nochk();
	fd = do_open(filename, O_RDONLY, 0);
	rechk();

	if (fd < 0)
	{
		goto done;
	}

	if (__do_fstat(fd, &st, TRUE) < 0)
	{
		goto err;
	}

	printk("size = %d\n", st.st_size);
	
	if (!(ptr = kmalloc(st.st_size, PageWait)))
	{
		goto err;
	}
	
	if (do_read(fd, ptr, st.st_size) < 0)
	{
		kfree(ptr);
		ptr = NULL;
	}
err:
	do_close(fd);
done:
	return ptr;
}
#else
void * get_file_buffer(const char *filename)
{
	void *ptr;
	int size;
	FILE *fp;
	int fd;
#ifndef WIN32
	struct stat st;
#endif
	fp = fopen(filename, "rb");
	if (!fp)
	{
		printf("open %s for reading failed!\n", filename);
		return NULL;
	}

	fd = fileno(fp);

#ifdef WIN32
	size = _filelength(fd);
#else
	if (fstat(fd, &st) < 0)
	{
		ptr = NULL;
		goto done;
	}

	size = st.st_size;
#endif
	if (size < 0)
	{
		ptr = NULL;
		goto  done;
	}

	ptr = elf_malloc(size * sizeof(char));
	if (!ptr)
	{
		goto done;
	}

	if (fread(ptr, size, 1, fp) != 1)
	{
		printf("read %d bytes failed!\n", size);
		elf_free(ptr);

		ptr = NULL;
		goto done;
	}


done:
	fclose(fp);
	return ptr;
}
#endif

int get_file_fd(const char *name)
{
        int fd;
        
#ifdef CNIX
        nochk();
	fd = do_open(name, O_RDONLY, 0);
	rechk();
#else
	FILE *fp;


	if (!(fp = fopen(name, "r")))
	{
		return -1;
	}

	fd = fileno(fp);
#endif	
	return fd;
}

void fdclose(int fd)
{
#ifdef CNIX
        do_close(fd);
#else
	FILE *fp;

#ifdef WIN32
	fp = _fdopen(fd, "r");
#else 
	fp = fdopen(fd, "r");
#endif
	fclose(fp);
#endif
}

#define MAX_LINE_SIZE	4

static char line_buffer[MAX_LINE_SIZE];
static int line_ptr;
static int line_size;

enum 
{
	STATE_SEEN_NORMAL,
	STATE_SEEN_CR,
	STATE_SEEN_LF
};

static char *__get_one_line(char *buff, int len, int fd, int state)
{
	int i;
	int left;
	int c;

	if (line_ptr >= line_size)
	{
#ifdef WIN32		
		line_size = _read(fd, &line_buffer[0], MAX_LINE_SIZE);
#elif defined(CNIX)
                line_size = do_read(fd, &line_buffer[0], MAX_LINE_SIZE);
#else
		line_size = read(fd, &line_buffer[0], MAX_LINE_SIZE);
#endif
		if (line_size <= 0)
		{
			return NULL;
		}

		line_ptr = 0;
	}

	left = line_size - line_ptr;

	for (i = 0; i < left; )
	{
		if (i >= len - 1)
		{
			buff[i] = '\0';
			return buff;
		}
		
		c = line_buffer[line_ptr++];

		if (state == STATE_SEEN_NORMAL)
		{
			if (c == '\r')
			{
				state = STATE_SEEN_CR;
				continue;
			} 
			else if (c == '\n')
			{
				buff[i] = '\n';
				break;
			}
			else
			{
				buff[i++] = c;
				continue;
			}
		}
		else if (state == STATE_SEEN_CR)
		{
			if (c == '\r')
			{
				continue;
			}
			else 
			{
				buff[i++] = c;
				state = STATE_SEEN_NORMAL;
				if (c == '\n')
				{
					i--;
					break;
				}
			}
		}

	}

	buff[i + 1] = '\0';

	if (i == left)
	{
		buff[i] = '\0';
		__get_one_line(&buff[i], len - i, fd, state);
	}
	
	return buff;
}

char *get_one_line(char *buff, int len, int fd)
{
	return __get_one_line(buff, len, fd, STATE_SEEN_NORMAL);
}

#ifdef CNIX
/* from libc */
char *strtok(char *s, const char *delim)
{
        static char *last;

        return strtok_r(s, delim, &last);
}

char *strtok_r(char *s, const char *delim, char **last)
{
        char *spanp;
        int c, sc;
        char *tok;


        if (s == NULL && (s = *last) == NULL)
                return (NULL);

        /*
         * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
         */
cont:
        c = *s++;
        for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
                if (c == sc)
                        goto cont;
        }

        if (c == 0) {           /* no non-delimiter characters */
                *last = NULL;
                return (NULL);
        }
        tok = s - 1;

        /*
         * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
         * Note that delim must have one NUL; we stop if we see that, too.
         */
        for (;;) {
                c = *s++;
                spanp = (char *)delim;
                do {
                        if ((sc = *spanp++) == c) {
                                if (c == 0)
                                        s = NULL;
                                else
                                        s[-1] = 0;
                                *last = s;
                                return (tok);
                        }
                } while (sc != 0);
        }
        /* NOTREACHED */
}

#endif

